#pragma once

#include<iostream>
#include<cstdio>
#include<queue>
#include<pthread.h>


const int gmaxcap = 5;


template<class T>
class BlockQueue
{
public:
    BlockQueue(const int& maxcap = gmaxcap)
    :_maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }
    void push(const T& in)//输入型参数, const&
    {
        pthread_mutex_lock(&_mutex);
        //if(is_full())的话, 假如生产者有10个, 消费者有1个, 当满的时候, 当消费者唤醒生产者的时候, 如果用的是broadcast, 会唤醒一批生产者, 而此时只有一个空位, 所以push的时候极有可能会出错改正用while循环
        while(is_full())
        {
            //pthread_cond_wait : 该函数调用的时候, 会以原子性的方式, 将锁释放，并将自己挂起
            //pthread_cond_wait : 该函数在被唤醒返回的时候, 会自动的重新获取你传入的锁
            pthread_cond_wait(&_pcond,&_mutex);
        }
        _q.push(in);
        //pthread_cond_signal : 这个函数可以放在临界区内部,也可以放在临界区外部
        pthread_cond_signal(&_ccond);
        pthread_mutex_unlock(&_mutex);
    }
    void pop(T* out)//输出型参数, *   输入输出型参数, &
    {
        pthread_mutex_lock(&_mutex);
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }
        *out = _q.front();
        _q.pop();
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }
private:
    bool is_empty()
    {
        return _q.empty();
    }
    bool is_full()
    {
        return _q.size() == _maxcap;
    }
private:
    std::queue<T> _q;
    int _maxcap;
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;
    pthread_cond_t _ccond;
};